﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using XcoAppSpaces.Core;

namespace SharedTextEditor
{
    public class DocumentClient
    {
        private XcoAppSpace space;
        private IList<CommunicationPartner> partners;


        public DocumentClient(IList<CommunicationPartner> partners)
        {
            this.partners = partners;
            space = new XcoAppSpace("tcp.port=0");
        }

        public event EventHandler PartnerDisconnected;


        // Check with ping message if partners are active
        // Remove partner when exception occured
        public void CheckIfPartnersActive()
        {
            while (true)
            {
                foreach (var partner in new List<CommunicationPartner>(partners))
                {
                    try
                    {
                        var port = space.Connect<PingMessage>(partner.Address);
                        var message = new PingMessage();

                        port.Post(message);
                        space.StopWorker(port);
                    }
                    catch (Exception)
                    {
                        //Remove partner when exception during communication occured
                        partners.Remove(partner);
                        if (PartnerDisconnected != null)
                            PartnerDisconnected(this, new EventArgs());
                    }
                }
                Thread.Sleep(1000);
            }
        }

        // Get document from address -> ReponseHandler gets called on response
        public void GetDocument(string address, Microsoft.Ccr.Core.Handler<DocumentMessage> responseHandler)
        {
            try
            {
                Console.WriteLine("[Client] GetDocument");
                var port = space.Connect<DocumentMessage>(address);
                var message = new DocumentMessage();
                message.ResponsePort = space.Receive<DocumentMessage>(responseHandler);

                port.Post(message);
                space.StopWorker(port);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e);
            }
        }

        private List<int> _previousLock = new List<int>();

        public void UnlockPrevious(IList<CommunicationPartner> partners)
        {
            LockUnlockLines(partners, _previousLock, false);
        }

        //Send locked or unlocked line numbers to all partners
        public void LockUnlockLines(IList<CommunicationPartner> partners, List<int> lineNumbers, bool lockLines)
        {
            if (lockLines)
            {
                _previousLock = lineNumbers;
            }

            Console.WriteLine("[Client] LockUnlockLines");
            foreach (var partner in new List<CommunicationPartner>(partners))
            {
                try
                {
                    var port = space.Connect<LockLinesMessage>(partner.Address);
                    var message = new LockLinesMessage();
                    message.LineNumbers = lineNumbers;
                    message.Lock = lockLines;

                    port.Post(message);
                    space.StopWorker(port);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error: " + e);
                }
            }
        }

        //Send changed lines to all partners
        public void ChangedLines(IList<CommunicationPartner> partners, Dictionary<int, string> updatedLines)
        {
            Console.WriteLine("[Client] ChangedLines");
            foreach (var partner in new List<CommunicationPartner>(partners))
            {
                try
                {
                    var port = space.Connect<UpdateLinesMessage>(partner.Address);
                    var message = new UpdateLinesMessage();
                    message.UpdatedLines = updatedLines;
                    port.Post(message);
                    space.StopWorker(port);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error: " + e);
                }
            }
        }

        public void Dispose()
        {
            space.Dispose();
        }

    }

}
